﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Student
{

    // Create the Node Type
    public class GeniusNode<Type>
    {

        // Declare the Data Holder
        public Type Data;

        // Declare the Linked Node
        public GeniusNode<Type> Next;

    }

    // Declare the List Type
    public class GeniusList<Type>
    {

        // Declare the List Front & End
        GeniusNode<Type> Front = new GeniusNode<Type>();
        GeniusNode<Type> End = new GeniusNode<Type>();

        // Function: Constructor
        public GeniusList()
        {

            // Assign the Null to Front & End
            this.Front = null;
            this.End = null;

        }

        // Function: Return the Number of Element in the List
        // Build : 1000 - Release Date : Oct 7th , 2013
        public int Count()
        {

            // Create the Counter
            int tmpCounter = 0;

            // Create the Temporary Node
            GeniusNode<Type> tmpNode = this.Front;

            // Traversing the List
            while (tmpNode != null)
            {

                // Increase the Counter
                tmpCounter++;

                // Move to the Next Node
                tmpNode = tmpNode.Next;

            }

            // Return the Counter
            return tmpCounter;

        }

        // Function: Return the Value of Element in given Position
        // Build : 1000 - Release Date : Oct 7th , 2013
        public Type Element(int iPosition)
        {

            // Validate the Position
            if (iPosition >= this.Count())
            {

                // Throw new Exception
                throw(new Exception("Out of Index"));

            }
            else
            {

                // Create the Temporary Node
                GeniusNode<Type> tmpNode = this.Front;

                // Create the Counter
                int tmpCounter = 0;

                // Traversing the List
                while (tmpCounter != iPosition)
                {

                    // Move to the Next Node
                    tmpNode = tmpNode.Next;

                    // Increase the Counter
                    tmpCounter++;

                }

                // Return the Node Data
                return tmpNode.Data;

            }

        }

        // Function: Return the Position of Element which matched with given Data
        // Build : 1000 - Release Date : Oct 7th , 2013
        public int Search(Type iData)
        {

            // Create the Temporary Node
            GeniusNode<Type> tmpNode = this.Front;

            // Create the Counter
            int tmpCounter = 0;

            // Traversing the List
            while (tmpNode != null && ! tmpNode.Data.Equals(iData))
            {

                // Move to the Next Node
                tmpNode = tmpNode.Next;

                // Increase the Counter
                tmpCounter++;

            }

            // Check the Temporary Node
            if (tmpNode == null)
            {

                // Throw new Exception
                throw(new Exception("Node Not Found !"));

            }
            else
            {

                // Return the Counter
                return tmpCounter;

            }

        }

        // Function: Append a new Element into the List
        // Build : 1000 - Release Date : Oct 7th , 2013
        public void Append(Type iData)
        {

            // Create a New Node
            GeniusNode<Type> newNode = new GeniusNode<Type>();

            // Set the Data for the New Node
            newNode.Data = iData;
            newNode.Next = null;

            // Check the List Status
            if (this.Front == null)
            {

                // Assign the New Node to List Front & End
                this.Front = newNode;
                this.End = newNode;

            }
            else
            {

                // Assign the New Node to the End of List
                this.End.Next = newNode;
                this.End = newNode;

            }

        }

        // Function: Traversing ( or Print ) all of List's Element
        // Build : 1000 - Release Date : Oct 7th , 2013
        public void Print()
        {

            // Create the Temporary Node
            GeniusNode<Type> tmpNode = new GeniusNode<Type>();

            // Assign the iList Front into the Temporary Node
            tmpNode = this.Front;

            // Traversing the List
            while (tmpNode != null)
            {

                // Print the Node Data
                Console.WriteLine(tmpNode.Data);

                // Move to the Linkded Node
                tmpNode = tmpNode.Next;

            }

            // Remove the Temporary Node
            tmpNode = null;

        }

        // Function: Insert a new Element after given Position
        // Build : 1000 - Release Date : Oct 7th , 2013
        public void Insert(Type iData, int iPosition)
        {

            // Validate the Position
            if (iPosition >= this.Count())
            {

                // Throw new Exception
                throw(new Exception("Out of Index"));

            }
            else
            {

                // Create a Temporary Node
                GeniusNode<Type> tmpNode = this.Front;

                // Create the Counter
                int tmpCounter = 0;

                // Go to the Target Position
                while (tmpNode != null && tmpCounter != iPosition)
                {

                    // Move to Next Node
                    tmpNode = tmpNode.Next;

                    // Increase the Counter
                    tmpCounter++;

                }

                // Create the New Node
                GeniusNode<Type> newNode = new GeniusNode<Type>();

                // Assign the Data into the newNode
                newNode.Data = iData;

                // Check the End of the List
                if (tmpNode.Next == null)
                {

                    // Set the New Node is the Ending Node
                    this.End = newNode;

                }
                else
                {

                    // Point the Next of New Node to Next of Temporary Node
                    newNode.Next = tmpNode.Next;

                }

                // Point the Next of Temporary Node to New Node
                tmpNode.Next = newNode;

            }

        }

        // Function: Remove the Element which matched with given Data
        // Build : 1000 - Release Date : Oct 7th , 2013
        public void Remove(int Position)
        {

            // Check the Position Value
            if (!(Position < this.Count()))
            {

                // Break the Operation
                return;

            }
            else
            {

                // Check the Length of this List
                if (this.Count() == 1)
                {

                    // Clear the List
                    this.Front = null;
                    this.End = null;

                }
                else
                {

                    // Create Temporary Node
                    GeniusNode<Type> tmpNode = this.Front;

                    // Case of the First Node
                    if (Position == 0)
                    {

                        // Change the Front of the List
                        this.Front = tmpNode.Next;

                        // Go to the Next Node
                        tmpNode = tmpNode.Next;

                    }
                    else
                    {

                        // Go to the Position
                        for (int X = 0; X < Position - 1; X++)
                        {

                            // Skip the Node
                            tmpNode = tmpNode.Next;

                        }

                        // Case of the Last Node
                        if (tmpNode.Next.Equals(this.End))
                        {

                            // Change the Ending Node
                            this.End = tmpNode;

                            // Remove the Ending Node
                            tmpNode.Next = null;

                        }
                        else
                        {

                            // Break the Junk Node
                            tmpNode.Next = tmpNode.Next.Next;

                        }

                    }

                }

            }

        }

        // Function: Swap Data of Two Nodes
        // Build : 1000 - Release Date : Oct 7th , 2013
        public void Swap(int tmpFirst, int tmpSecond)
        {

            // Validate the Positions
            if (tmpFirst >= this.Count() || tmpSecond >= this.Count())
            {

                // Throw new Exception
                throw (new Exception("Invalid Position (s)"));

            }
            else
            {

                // Storage the First Element's Data
                Type tmpStorage = this.Element(tmpFirst);

                // Create the Temporary Node
                GeniusNode<Type> tmpNode = this.Front;

                // Create the Counter
                int tmpCounter = 0;

                // Go to the First Element
                while (tmpCounter != tmpFirst)
                {

                    // Move to the Next Node
                    tmpNode = tmpNode.Next;

                    // Increase the Counter
                    tmpCounter++;

                }

                // Change Data of First Element
                tmpNode.Data = this.Element(tmpSecond);

                // Reset the Temporary Node
                tmpNode = this.Front;

                // Reset the Counter
                tmpCounter = 0;

                // Go to the Second Element
                while (tmpCounter != tmpSecond)
                {

                    // Move to the Next Node
                    tmpNode = tmpNode.Next;

                    // Increase the Counter
                    tmpCounter++;

                }

                // Change Data of Second Element
                tmpNode.Data = tmpStorage;


            }

        }

        // Function : Convert the Genius List into List
        // Build : 1000 - Release Date : Oct 17th , 2013
        public List<Type> ToList()
        {

            // Declare the Result List
            List<Type> resultList = new List<Type>();

            // Create the Temporary Node
            GeniusNode<Type> tmpNode = new GeniusNode<Type>();

            // Assign the iList Front into the Temporary Node
            tmpNode = this.Front;

            // Traversing the List
            while (tmpNode != null)
            {

                // Insert into Result List
                resultList.Add(tmpNode.Data);

                // Move to the Linkded Node
                tmpNode = tmpNode.Next;

            }

            // Remove the Temporary Node
            tmpNode = null;

            // Return the result List
            return resultList;

        }
        
    }
}
